package com.sliansoft.wechat.appcenter.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.ParseException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.sliansoft.wechat.appcenter.context.WeixinContext;
import com.sliansoft.wechat.appcenter.context.WeixinFinalValue;
import com.sliansoft.wechat.appcenter.kit.WeixinKit;
import com.sliansoft.wechat.appcenter.model.AgentInfo;
import com.sliansoft.wechat.appcenter.model.App;
import com.sliansoft.wechat.appcenter.model.CorpToken;
import com.sliansoft.wechat.appcenter.model.Menuone;
import com.sliansoft.wechat.appcenter.model.Menutwo;
import com.sliansoft.wechat.appcenter.model.SuiteWithBLOBs;
import com.sliansoft.wechat.appcenter.model.WeixinMenu;
import com.sliansoft.wechat.appcenter.service.IAgentInfoService;
import com.sliansoft.wechat.appcenter.service.IAppService;
import com.sliansoft.wechat.appcenter.service.ICorpTokenService;
import com.sliansoft.wechat.appcenter.service.IMenuOneService;
import com.sliansoft.wechat.appcenter.service.IMenuTwoService;
import com.sliansoft.wechat.appcenter.service.ISuiteService;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@Controller
public class ThirdAppController {
	
	@Inject
	private ISuiteService suiteService;
	@Inject
	private IAppService appService;
	@Inject
	private IMenuOneService menuOneService;
	@Inject
	private IMenuTwoService menuTwoService;
	@Inject
	private IAgentInfoService agentInfoService;
	@Inject
	private ICorpTokenService corpTokenService;
	
	
	/**
	 * 服务事件接受URL,主要获取suite_ticket及变更、取消授权信息
	 * 
	 * @return
	 * @throws IOException
	 * @throws AesException
	 * @throws DocumentException
	 * @throws ParseException
	 */
	@RequestMapping("/recServiceMsg/{suite_id}")
	public void recServiceMsg(@PathVariable String suite_id, HttpServletResponse resp, HttpServletRequest req)
			throws IOException, AesException, DocumentException {
		System.out.println("微信服务器发来系统事件");
		// SuiteWithBLOBs suite = suiteService.selectBySuiteId(suite_id);
		Element root = parseMsg(resp, req, suite_id);// 获取服务信息解析后的数据

		String InfoType = root.element("InfoType").getText();// 获取服务信息类型
//		System.out.println("InfoType:"+InfoType);
		if ("suite_ticket".equals(InfoType)) {// 推送了suite_ticket，10分钟推送一次
			String suiteTicket = root.element("SuiteTicket").getText();
			WeixinContext.setSuiteTicket(suite_id, suiteTicket);// 保存suite_ticket
			System.out.println("suiteTicket:" + suiteTicket);
		}
		if ("change_auth".equals(InfoType)) {// 变更授权
			
			Map<String,String> newAgentApp=new HashMap<String,String>();
			System.out.println("变更授权");
			String AuthCorpId = root.element("AuthCorpId").getText();// 授权方企业号的corpid
			changeAuth(suite_id,AuthCorpId,newAgentApp);
			
		}
		if ("cancel_auth".equals(InfoType)) {// 取消授权
			System.out.println("取消授权");
		}
		resp.getWriter().write("success");
	}
	/**
	 * 获取微信服务器推送的服务信息并解密
	 * 
	 * @param resp
	 * @param req
	 * @param suite
	 * @return
	 * @throws IOException
	 * @throws AesException
	 * @throws DocumentException
	 */
	private Element parseMsg(HttpServletResponse resp, HttpServletRequest req, String suite_id)
			throws IOException, AesException, DocumentException {
		
		// 获取微信服务器推送的密文
		InputStream in = req.getInputStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String str = "";
		String line = "";
		while ((line = br.readLine()) != null) {
			str += line;
		}
//		 System.out.println(str);

		// 解密
		SuiteWithBLOBs suite = suiteService.selectBySuiteId(suite_id);
		String token = suite.getToken();
		String encodingAesKey = suite.getEncodingaeskey();
		String suiteId = suite.getSuiteId();
		
		String sReqMsgSig = req.getParameter("msg_signature");
		String sReqTimeStamp = req.getParameter("timestamp");
		String sReqNonce = req.getParameter("nonce");
		WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, suiteId);
		String xml = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, str);
//		 System.out.println("解密"+xml);

		// 获取解密后的DOM树
		Document document = DocumentHelper.parseText(xml);
		Element root = document.getRootElement();
		return root;
	}
	/**
	 * 
	 * 安装套件中的应用，如果appId的值为-1，则可以对套件中的应用都授权安装；如果不为-1，则说明是要安装指定的应用。
	 * 
	 * @param modelAndView
	 * @return
	 */
	@RequestMapping("/installApp/{suite_id}/{appId}")
	public ModelAndView installApp(@PathVariable(value="suite_id") String suite_id, @PathVariable(value="appId") Integer appId,ModelAndView modelAndView, HttpServletRequest req) {
		SuiteWithBLOBs suite = suiteService.selectBySuiteId(suite_id);
		
		String suite_access_token = WeixinKit.getSuiteAccessToken(suite);// 获取suite_access_token
		System.out.println("suite_access_token:" + suite_access_token);// 输出suite_access_token
		
		String pre_auth_code = WeixinKit.getPreAuthCode(suite_access_token, suite);// 获取pre_auth_code
		System.out.println("pre_auth_code:" + pre_auth_code);// 输出pre_auth_code
		
		//如果appId ！= -1 则说明需要对单个特定应用授权，那么就需要对该授权过程进行授权设置，如果不进行默认可以授权套件中的所有应用
		if(appId>0){
			//如果从应用界面进行安装则只可以安装这一个应用
			String url=WeixinFinalValue.CONFIGURING_AUTH.replace("SUITE_ACCESS_TOKEN", suite_access_token);
			Map<String, Object> map = new HashMap<String, Object>();
			Map<String, Integer> map1 = new HashMap<String, Integer>();
			map.put("pre_auth_code", pre_auth_code);
			map1.put("appid", appId);
			map.put("session_info",map1 );
			
			String json = JSONObject.fromObject(map).toString();
			String jsonresult = WeixinKit.postReq(url, json, "application/json");
//				System.out.println("返回结果:" + jsonresult);
		}
		
		//String redirect_uri = "http://wxin.xlstny.cn/appcenter-web/operateApp/" + suite_id;// 授权成功回调地址，返回第三方供应商首页
		String redirect_uri = WeixinFinalValue.REDIRECT_URI;// 授权成功回调地址，调用operateApp方法后返回第三方供应商首页
		redirect_uri = redirect_uri.replace("suite_id", suite_id);
		String state = "david";
		//存以下参数是因为跳转到微信验证也需要以下参数
		modelAndView.addObject("suite", suite);
		modelAndView.addObject("suite_id", suite_id);
		modelAndView.addObject("pre_auth_code", pre_auth_code);
		modelAndView.addObject("redirect_uri", redirect_uri);
		modelAndView.addObject("state", state);
		modelAndView.setViewName("AuthPage");
		return modelAndView;
	}
	/**
	 * 确定授权之后
	 * 获取永久授权码，操作app，增加菜单栏
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping("/operateApp/{suite_id}")
	public String operateApp(@PathVariable String suite_id, HttpServletRequest req) {
		
		System.out.println("operateApp");
		SuiteWithBLOBs suite = suiteService.selectBySuiteId(suite_id);
		String suite_access_token = WeixinKit.getSuiteAccessToken(suite);
		String url = WeixinFinalValue.GET_PERMANENT_CODE.replace("SUITE_ACCESS_TOKEN", suite_access_token);
		String auth_code = req.getParameter("auth_code");//临时授权码
		System.out.println("auth_code:" + auth_code);
		
		Map<String, String> map = new HashMap<String, String>();
		map.put("suite_id", suite_id);
		map.put("auth_code", auth_code);
		String json = JSONObject.fromObject(map).toString();
		String jsonresult = WeixinKit.postReq(url, json, "application/json");
		System.out.println("获取永久授权码时返回的所有json:" + jsonresult);
		
		JSONObject jsonObject = JSONObject.fromObject(jsonresult);
		Map<String, Object> map_result = JSONObject.fromObject(jsonObject);
		String permanent_code = (String) map_result.get("permanent_code");//获取永久授权码
		String access_token=(String)map_result.get("access_token");//get AccessToken
		System.out.println("access_token："+access_token);
		// auth_corp_info授权方企业信息
		JSONObject json_auth_corp_info = (JSONObject) map_result.get("auth_corp_info");
		System.out.println(map_result.get("auth_corp_info"));
		Map<String, String> map_auth_corp_info = JSONObject.fromObject(json_auth_corp_info);
		String copr_id = map_auth_corp_info.get("corpid");//获取企业号的corp_id
		
		
		Map<String, String> newAgentApp = new HashMap<String, String>();
		processAuthInfoJson(map_result, suite_id, copr_id,newAgentApp);
		/**
		 * 1、判断数据库中是否存在获取corp_id和suite_id对应的access_token。
		 * 2、存在则不处理
		 * 3、不存在则将corp_id、suite_id、permanent_code及对应的access_token保存进数据库
		 */
		CorpToken corpToken=new CorpToken();
		corpToken.setAccessToken(access_token);
		corpToken.setCorpId(copr_id);
		corpToken.setSuiteId(suite_id);
		corpToken.setPermanentCode(permanent_code);
		corpTokenService.saveOrUpdateCorpToken(corpToken);
		System.out.println("newAgentApp:"+newAgentApp);
		for(String key:newAgentApp.keySet()){
			System.out.println("key="+key);
			addMenu(access_token,suite_id,Integer.parseInt(newAgentApp.get(key)),key,copr_id);
			//configApp(corpToken,key,suite_access_token);
		}
		System.out.println("---end---");
		return "redirect:/index.jsp";
		
		//return "redirect:/operateApp/" + suite_id;
	}
	/**
	 * 添加自定义菜单
	 * 
	 * @param access_token
	 * @param appId 
	 * @param suite_id 
	 */
	private void addMenu(String access_token,String suite_id, int appId, String agentId,String corpId) {
		
		String url = WeixinFinalValue.MENU_ADD;
		url = url.replace("ACCESS_TOKEN", access_token);
		url = url.replace("AGENTID", agentId);// AgentID的意思是应用的ID,从获取企业号的授权信息中获取

		List<WeixinMenu> wms = new ArrayList<WeixinMenu>();
		//System.out.println("suite_id:"+suite_id);
		//System.out.println("appId:"+appId);
		App app = appService.selectBySuiteIdAndAppId(suite_id, appId);
		
		int Id = app.getId(); //获取菜单对应的app的id，而不是appId
		List<Menuone> menuoneList = menuOneService.selectByAppId(Id);//获取一级菜单的list
		for(int i = 0; i<menuoneList.size();i++){
			List<Menutwo> menutwoList = menuTwoService.selectByMenuoneId(menuoneList.get(i).getId());//获取二级菜单的list
			if(menutwoList.size()>0){//根据二级菜单是否存在来决定是否设置sub_button
				WeixinMenu wm = new WeixinMenu(); //一级菜单
				wm.setName(menuoneList.get(i).getMenuoneName());//设置一级菜单的name
				List<WeixinMenu> wmSubList = new ArrayList<WeixinMenu>();//二级菜单的列表
				for(int j=0;j<menutwoList.size();j++){
					WeixinMenu wmSub = new WeixinMenu();//二级菜单
					wmSub.setId(i);
					wmSub.setName(menutwoList.get(j).getMenutwoName());
					wmSub.setType(menutwoList.get(j).getMenutwoType());
					if("view".equals(menutwoList.get(j).getMenutwoType())){
						//String codeUrl=WeixinFinalValue.Get_CODE.replace("CORPID", corpId).replace("REDIRECT_URI", menutwoList.get(j).getMenutwoUrl()).replace("STATE", corpId);
						//wmSub.setUrl(codeUrl);
						wmSub.setUrl(menutwoList.get(j).getMenutwoUrl()+"?corpId="+corpId);
						System.out.println("二级菜单URL："+menutwoList.get(j).getMenutwoUrl()+"?corpId="+corpId);
					}else{
						wmSub.setKey(menutwoList.get(j).getMenutwoKey());
					}
					wmSubList.add(wmSub);
				}
				//System.out.println(wmSubList);
				wm.setSub_button(wmSubList);
				wms.add(wm);
			}else{
				WeixinMenu wm = new WeixinMenu();//一级菜单
				wm.setId(i);
				wm.setName(menuoneList.get(i).getMenuoneName());
				wm.setType(menuoneList.get(i).getMenuoneType());
				if("view".equals(menuoneList.get(i).getMenuoneType())){
					//System.out.println("-------"+menuoneList.get(i).getMenuoneUrl()+"corpId=="+corpId+"======================="+agentId+"---"+appId);
					//String codeUrl=WeixinFinalValue.Get_CODE.replace("CORPID", corpId).replace("REDIRECT_URI", menuoneList.get(i).getMenuoneUrl()).replace("STATE", corpId);
					//wm.setUrl(codeUrl);
					wm.setUrl(menuoneList.get(i).getMenuoneUrl()+"?corpId="+corpId);
					System.out.println("一级菜单URL："+menuoneList.get(i).getMenuoneUrl()+"?corpId="+corpId);
				}else{
					wm.setKey(menuoneList.get(i).getMenuoneKey());
				}
				wms.add(wm);
			}
		}
		if(wms.size()>0){
			Map<String, List<WeixinMenu>> maps = new HashMap<String, List<WeixinMenu>>();
			maps.put("button", wms);
			String json = JSONObject.fromObject(maps).toString();
			//System.out.println("json+"+json);
			String result = WeixinKit.postReq(url, json, "application/json");
			System.out.println("添加菜单栏:" + result);
		}
	}
	/**
	 * 配置应用
	 * @param corpToken
	 */
	private void configApp(CorpToken corpToken,String agentid,String suiteAccessToken) {
		// TODO Auto-generated method stub
		Map<String,Object> conf=new HashMap<>();
		conf.put("suite_id", corpToken.getSuiteId());
		conf.put("auth_corpid",corpToken.getCorpId());
		conf.put("permanent_code", corpToken.getPermanentCode());
		Map<String,Object> agent=new HashMap<>();
		agent.put("agentid", agentid);
//		agent.put("redirect_domain", "boomshakalaka520.6655.la");
//		agent.put("redirect_domain", "wxin.xlstny.cn");
		agent.put("redirect_domain", WeixinFinalValue.REDIRECT_DOMAIN);
		agent.put("isreportuser", 1);
		agent.put("isreportenter", 1);
		conf.put("agent",agent);
		String json = JSONObject.fromObject(conf).toString();
		String jsonresult = WeixinKit.postReq(WeixinFinalValue.CONF_APP.replace("SUITE_ACCESS_TOKEN", suiteAccessToken), json, "application/json");
		System.out.println(jsonresult);
//		JSONObject jsonObject = JSONObject.fromObject(jsonresult);
//		Map<String, String> mapresult = JSONObject.fromObject(jsonObject);
	}
	
	/**
	 * 发生变更授权后，获取企业号的授权信息
	 * @param suite_id
	 * @param authCorpId
	 * @param newAgentApp 
	 */
	private void changeAuth(String suite_id, String authCorpId, Map<String, String> newAgentApp) {
		CorpToken corpToken =corpTokenService.selectByCorpIdAndSuiteId(authCorpId, suite_id);
		String suiteAccessToken=WeixinKit.getSuiteAccessToken(suiteService.selectBySuiteId(suite_id));
		String url=WeixinFinalValue.GET_CORP_AUTH_INFO.replace("SUITE_ACCESS_TOKEN", suiteAccessToken);
		Map<String, String> map = new HashMap<String, String>();
		map.put("suite_id", suite_id);
		map.put("auth_corpid", authCorpId);
		map.put("permanent_code", corpToken.getPermanentCode());
		String json = JSONObject.fromObject(map).toString();
		String jsonresult = WeixinKit.postReq(url, json, "application/json");
		JSONObject jsonObject = JSONObject.fromObject(jsonresult);
		Map<String, Object> map_result = JSONObject.fromObject(jsonObject);
		processAuthInfoJson(map_result, suite_id,authCorpId,newAgentApp);
	}
	/**
	 * 在变更授权或者授权完成后拿到的json数据，对其进行处理，更新appId与agentId的关系，处理Auth_info
	 * @param newAgentApp 
	 * @param jsonresult
	 */
	private void processAuthInfoJson(Map<String, Object> map_result,String suite_id,String copr_id, Map<String, String> newAgentApp) {
		//auth_info授权信息
		JSONObject json_auth_info = (JSONObject) map_result.get("auth_info");
		Map<String, Object> map_auth_info = JSONObject.fromObject(json_auth_info);
		System.out.println("auth_info:"+json_auth_info+" map_auth_info:"+map_auth_info);
		
		//判断json_auth_info是否有数据
		if (json_auth_info!=null) {
			/**
			 * 1、根据agent_list_map获取agent_app的对应字符串
			 * 2、根据Corp_id和suite_id获取数据库中的agent_app的对应字符串 
			 * 3、如果存在则比对上面获取的两个字符串，得到新授权的应用的agent_id和app_id，并用步骤1获取的agent_app的对应字符串更新数据库中的相应字段
			 * 4、不存在则解析1中获取的字符串得到新授权的应用的agent_id和app_id，并将corp_id、suite_id及步骤1获取的字符串封装成一个对象存进数据库
			 */
			//agent授权的应用信息
			JSONArray json_agent_array = (JSONArray) map_auth_info.get("agent");
			List<Map<String, Object>> agent_list_map = new ArrayList<Map<String, Object>>();// 信息从这里取
			for (int i = 0; i < json_agent_array.size(); i++) {
				JSONObject json_agent = json_agent_array.getJSONObject(i);
				Map<String, Object> map_agent = JSONObject.fromObject(json_agent);
				agent_list_map.add(map_agent);
			}
			StringBuilder agentApp = new StringBuilder();
			
			//通过AgentID遍历获取AppId,得到agentId与appId的对应关系
			for (Map<String, Object> map_agent : agent_list_map) {
				String agentId = map_agent.get("agentid").toString();
				String appId = map_agent.get("appid").toString();
				agentApp.append(agentId + "-" + appId + " ");
			}
			
			//根据CorpId与suiteId的AgentInfo若为空，则将得到的数据存入数据库；否则更新
			AgentInfo agentInfo = agentInfoService.selectByCorpIdAndSuiteId(copr_id, suite_id);
			if (agentInfo == null) {
				agentInfo = new AgentInfo();
				agentInfo.setAgentApp(agentApp.toString());
				agentInfo.setCorpId(copr_id);
				agentInfo.setSuiteId(suite_id);
				newAgentApp.clear();
				for (Map<String, Object> map_agent : agent_list_map) {
					String agentId = map_agent.get("agentid").toString();
					String appId = map_agent.get("appid").toString();
					newAgentApp.put(agentId, appId);
				}
				agentInfoService.saveAgentInfo(agentInfo);
			} else {
				if (!compare(agentApp.toString(), agentInfo.getAgentApp(),newAgentApp)) {
					agentInfo.setAgentApp(agentApp.toString());
					agentInfoService.updateAgentInfo(agentInfo);
				}
			}
		}else{
			//如果没有说明用户将该套件的应用全部取消授权，则删除数据库中的相关数据
			agentInfoService.deleteAgentInfoByCorpIdSuiteId(copr_id, suite_id);
			corpTokenService.deleteCorpTokenByCorpIdSuiteId(copr_id, suite_id);
		}
	}
	
	
	/**
	 * 比较该企业号授权的应用与之前拿到的一致，若不一致查看是否有授权的应用并记录
	 * @param agentApp
	 * @param lastAgentApp
	 * @param newAgentApp 
	 * @return
	 */
	private boolean compare(String agentApp, String lastAgentApp, Map<String, String> newAgentApp) {
		boolean flag=true;
		List<String> agentAppList = java.util.Arrays.asList(agentApp.trim().split(" "));
		List<String> lastAgentAppList = java.util.Arrays.asList(lastAgentApp.trim().split(" "));
		for (String string : agentAppList) {
			//System.out.println(string);
			if (!lastAgentAppList.contains(string)){
				if(flag){
					newAgentApp.clear();
					flag=false;
				}
				String[] newAA=string.trim().split("-");
				newAgentApp.put(newAA[0], newAA[1]);
				//System.out.println("newAgentApp:"+newAgentApp);
			}
		} 
		//System.out.println(newAgentApp);
		if (agentApp.length()==lastAgentApp.length()) {
			if(newAgentApp.isEmpty())
				return true;
			return false;
		}else{
			return false;
		}
	}
}
